#include <iostream>
#include <concepts>


template <typename T>
concept CONSTRAN1 = requires(T t){
    t.value_type;
};

template <typename T>
concept CONSTRAN2 = requires{
    typename T::value_type;
};

template <CONSTRAN2 T>
struct iterator_traits {
    typedef typename T::value_type value_type;
};

/*
template <class T>
struct iterator_traits<T*> {
    typedef T value_type;
};

template <class T>
struct iterator_traits<const T*> {
    typedef T value_type;
};
*/
template <class T>
struct MyIter {
    typedef T value_type;
    T * ptr;
    MyIter(T * p = 0) : ptr (p) {};
    T& operator* () const { return *ptr;}
};

template <class I>
typename iterator_traits<I>::value_type
get (I ite) {
    std::cout << "normal version" << std::endl;
    return *ite;
}

int main() {
    int i = 3;
    const int k = 3;
    MyIter<int> v(&i);
    std::cout << get(v) << std::endl;
   // std::cout << get(&i) << std::endl;
   // std::cout << get(&k) << std::endl;
    return 0;
}